/**
 * @file   MiraVector3D.cpp
 * @author Josep Sabater (jsabaterm@el.ub.edu)
 * @date   October, 2015
 * @version 1.0.0
 * @ingroup MiraGeometryLib
 * @brief  Implementation of a vector of 3 dimensions.
 *
 *
 */

#include <cmath>
#include <algorithm>
#include <iostream>

#include "MiraVector3D.h"
#include "MiraVector2D.h"
#include "MiraMath.h"

using namespace MiraUtilUBLib;

namespace MiraGeometryLib{

    const int Vector3D::zeroRoundDigits_ = 6;

    Vector3D& Vector3D::operator = (Vector3D v) {
        swap_(v);
        return *this;
    }

    Vector3D Vector3D::operator + (const Vector3D& v) const {
        return Vector3D(x_+v.x_, y_+v.y_, z_+v.z_);
    }

    Vector3D Vector3D::operator - (const Vector3D& v) const {
        return Vector3D(x_-v.x_, y_-v.y_, z_-v.z_);
    }

    /** Non-member friend function for << operator
     */
    std::ostream& operator << (std::ostream& os, const Vector3D& v){
        return os << "Vector3D (" << v.x_ << "," << v.y_ << "," << v.z_ << ")";
    }

    double Vector3D::squaredNorm() const { return (x_*x_ + y_*y_ + z_*z_); }
    double Vector3D::norm() const { return std::sqrt( squaredNorm() ); }
    Vector3D Vector3D::cross (const Vector3D& v) const {
        return Vector3D(y_*v.z_, z_*v.x_, x_*v.y_) -
            Vector3D(z_*v.y_, x_*v.z_, y_*v.x_ );
    }
    
    bool Vector3D::isZero() const {
        double zero = sqrt(pow(x_, 2) + pow(y_, 2) + pow(z_, 2));
        return (Math::round(zero, Vector3D::zeroRoundDigits_) == 0.);
    }
    
    void Vector3D::swap_(Vector3D& v) {
        std::swap(x_, v.x_);
        std::swap(y_, v.y_);
        std::swap(z_, v.z_);
    }
}
